﻿//
// Copyright (c) 2024 BPer
//
#include <bperice/BPerRtcStun.h>
#include <bperice/BPerRtcSocket.h>
#include <bpersrs/BPerSrsConnection.h>

#include <bpersdp/BPerSdp.h>
#include <bperjson/BPerJson.h>

#include <bperutil/sys/BPerLog.h>
#include <bperutil/sys/BPerCString.h>
#include <bperrtc/BPerRtcConnection.h>
#include <bperutil/sys/BPerHttp.h>
typedef struct{
	int32_t retcode;
	char* serverIp;
	char* sdp;
	char* sessionid;
}SrsSdpResponseType;

#define BPer_SDP_BUFFERLEN 1024*12

void bPer_destroy_srsresponse(SrsSdpResponseType* srs){
	if(srs==NULL) return;
	bPer_free(srs->sdp);
	bPer_free(srs->serverIp);
	bPer_free(srs->sessionid);
}

int32_t bPer_sdp_querySrs(BPerRtcSession* session,SrsSdpResponseType* srs,int32_t isplay,char* ip,int32_t port,char* purl, char* psdp)
{

	int32_t err=BPer_Ok;

	char* sdp=(char*)bPer_calloc(1,BPer_SDP_BUFFERLEN);
	if(bPer_http_post(BPerFalse,session->context.avinfo->sys.familyType,sdp,ip, port, purl, (uint8_t*)psdp, bPer_strlen(psdp))){
		bPer_free(sdp);
		return bPer_error_wrap(1,"query srs sdp failure!");
	}

	BPerJsonReader reader;
	char* p=bPer_strstr(sdp,"{");
	if(p==NULL) return ERROR_STRING;

	if(bPer_create_jsonReader(&reader,p)!=BPer_Ok){
		bPer_error("read srs response json error!");
		err=ERROR_STRING;
		goto cleanup;
	}

	BPerJson* jcode = reader.getObjectItemCaseSensitive(reader.session, "code");
	if (reader.isNumber(jcode))
	{
		err=jcode->valueint==0?BPer_Ok:ERROR_SERVER_ConnectFailure;
		if(err!=BPer_Ok) goto cleanup;
	}

	srs->retcode=jcode->valueint;
	BPerJson* server = reader.getObjectItemCaseSensitive(reader.session, "server");
	BPerJson* sessionid = reader.getObjectItemCaseSensitive(reader.session, "sessionid");
	BPerJson* jsdp = reader.getObjectItemCaseSensitive(reader.session, "sdp");
	if (reader.isString(server) && (server->valuestring != NULL))
	{
		srs->serverIp=(char*)bPer_calloc(bPer_strlen(server->valuestring)+1,1);
		bPer_memcpy(srs->serverIp,server->valuestring,bPer_strlen(server->valuestring));

	}

	if (reader.isString(sessionid) && (sessionid->valuestring != NULL))
	{
		srs->sessionid=(char*)bPer_calloc(bPer_strlen(sessionid->valuestring)+1,1);
		bPer_memcpy(srs->sessionid,sessionid->valuestring,bPer_strlen(sessionid->valuestring));

	}

	if (reader.isString(jsdp) && (jsdp->valuestring != NULL))
	{
		srs->sdp=(char*)bPer_calloc(bPer_strlen(jsdp->valuestring)+1,1);
		bPer_cstr_replace(jsdp->valuestring,srs->sdp, "\r\n", "\n");
	}

	cleanup:
	bPer_destroy_jsonReader(&reader);
	bPer_free(sdp);
	return err;
}

int32_t bPer_srs_getSignal(BPerRtcSession* session,SrsSdpResponseType* srs,char* sdp) {
	int32_t err = BPer_Ok;
	BPerRtcDirection role=session->context.streamConfig->direction;
	const char* roleStr=role==BPerRecvonly?"play":"publish";

	char apiStr[256]={0};
	char streamurl[256]={0};

	bPer_sprintf(apiStr,sizeof(apiStr),"http://%s:%d/rtc/v1/%s/",session->context.streamConfig->remoteIp, session->context.streamConfig->remotePort,roleStr);
	bPer_sprintf(streamurl,sizeof(streamurl),"webrtc://%s:%d/%s/%s",session->context.streamConfig->remoteIp,
			session->context.streamConfig->remotePort, session->context.streamConfig->app, session->context.streamConfig->stream);

	BPerJsonWriter writer;
	bPer_create_jsonWriter(&writer);

	writer.addStringToObject(writer.session,"capi",apiStr);
	writer.addStringToObject(writer.session,"streamurl",streamurl);
	writer.addNullToObject(writer.session,"clientip");
	writer.addStringToObject(writer.session,"sdp",sdp);
	char *srsSdp=writer.printUnformatted(writer.session);
	char apiurl[256] ;
	bPer_memset(apiurl,0,sizeof(apiurl));

	bPer_sprintf(apiurl,sizeof(apiurl), "rtc/v1/%s/", roleStr);
	err=bPer_sdp_querySrs(session,srs,role==BPerRecvonly?1:0,(char*)session->context.streamConfig->remoteIp,session->context.streamConfig->remotePort,apiurl, srsSdp);


	bPer_free(srsSdp);

	return err;
}

int32_t bPer_srs_connectRtcServer(BPerRtcConnection* conn){
	BPerRtcSession* session=conn->session;
	int err=BPer_Ok;
	SrsSdpResponseType srs;
	bPer_memset(&srs,0,sizeof(SrsSdpResponseType));

	//session->context.avinfo->rtc.enableHttpServerSdp=BPerTrue;

	char *tsdp=NULL;
	conn->createOffer(session, &tsdp);

	if(tsdp) conn->setLocalDescription(session,tsdp);
	if ((err=bPer_srs_getSignal(conn->session,&srs,tsdp))  == BPer_Ok) {
		conn->setRemoteDescription(conn->session,srs.sdp);
	}
	bPer_free(tsdp);
	bPer_destroy_srsresponse(&srs);
    return err;
}
